Skip to content

feat(ui): WebUI modernization PR6 — streaming-safe markdown tokenizer, golden tests, strict CSP - #114

Closed
jkyberneees wants to merge 1 commit into
feat/webui-modernization-5from
feat/webui-modernization-6
Closed

feat(ui): WebUI modernization PR6 — streaming-safe markdown tokenizer, golden tests, strict CSP#114
jkyberneees wants to merge 1 commit into
feat/webui-modernization-5from
feat/webui-modernization-6

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Summary

Sixth PR of the WebUI modernization roadmap — Phase 3b: streaming-safe markdown + golden tests + strict CSP. Stacked on #113 (feat/webui-modernization-5).

Streaming-safe markdown tokenizer (ui/js/markdown.js)

The old regex pipeline broke visibly while a response streamed — an unterminated ** or ``` rendered raw garbage until closed. The rewrite is a line-based block parser (code-fence state machine first, then headers/hr/lists/paragraphs) feeding a left-to-right inline span tokenizer, with asymmetric termination rules:

  • Unterminated fence → closed by EOF, renders as an (open) code block — the desired streaming behavior
  • Unterminated inline constructs (**bold, `code`, ~~strike~~) → render literally
  • The DOM contract is unchanged (code-block/cb-header/cb-lang/cb-copy, h1h4, ul/ol, p), links keep the exact scheme allowlist (http/https/mailto/relative; javascript:/data:/vbscript: neutralized) and target="_blank" rel="noopener noreferrer", and *italic* still doesn't trigger inside words (a*b*c)

Golden tests (ui/js/markdown.test.js, CI)

  • 26 tests on the built-in node --test runner: every block type, inline spans, scheme allowlist (incl. paren-in-URL edge), <script> escaping, unterminated fence/bold/code/strike, and a golden multi-feature document.
  • New ui-js job in test.yml (setup-node, node --test "cmd/odek/ui/js/**/*.test.js"); run instructions added to docs/DEVELOPMENT.md.
  • escape.js extracted as a leaf module so the tokenizer is testable under Node without DOM/localStorage side effects (utils.js re-exports).

Strict CSP (serve.go)

Now that every inline event handler was eliminated in PR5, script-src 'self' is possible. The static handler sets the full policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'none'; form-action 'none' (style-src 'unsafe-inline' only for the few style="display:none" attributes). This closes the residual XSS surface that markup sanitization alone couldn't reach. X-Frame-Options: DENY stays for legacy browsers.

Verification

  • node --test: 26 pass, 0 fail ✅; node --check all 13 UI JS files ✅
  • go build, go vet, full cmd/odek suite ✅ (existing CSP header test still passes)
  • Smoke test: CSP header confirmed on / and /app.js
  • Behavior eyeball: full-feature doc renders identically to the old pipeline; **bold → literal; unterminated fence → open code block ✅

…, golden tests, strict CSP

- Replace the regex-pipeline markdownToHtml with a hand-written
  line-based block parser + inline tokenizer. Unterminated fenced code
  blocks render their collected lines as a code block (EOF = fence
  close); unterminated inline constructs (**, backtick, ~~) render
  literally, so partial markdown no longer flashes broken markup while
  streaming. DOM contract preserved (h1-h4, hr, code-block/cb-header/
  cb-lang/cb-copy, ul/ol, p/br); .cb-copy is now a <button> (delegated
  clicks in render.js) with a UA-style reset in style.css.
- Extract escapeHtml/escapeAttr into leaf js/escape.js (re-exported by
  utils.js) so markdown.js is testable under Node without a DOM.
- Golden tests in js/markdown.test.js (node:test, 26 tests) covering
  every block/span type, streaming edge cases, link scheme allowlist,
  and HTML escaping; new ui-js CI job.
- Strict Content-Security-Policy on static responses (script-src
  'self', no inline scripts); frame-ancestors folded into the CSP.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
odek a712b3d Commit Preview URL

Branch Preview URL
Jul 26 2026, 01:29 PM

@jkyberneees

Copy link
Copy Markdown
Contributor Author

Superseded: this stacked chain was merged directly into main (merge commit 9ae5e46), together with #109. All changes from this PR are on main.

@jkyberneees
jkyberneees deleted the feat/webui-modernization-6 branch July 26, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant